﻿#include "ssUnixCallStack.h"
#include "execinfo.h"
#include <sstream>

namespace StarSeeker
{
    void ssUnixCallStack::ParseName(char* str, std::string& exe, std::string& addr)
	{
		char* strTemp = str;
		char* addrTemp = str;
		while (*strTemp != 0)
		{
			if (*strTemp == '(')
				exe.assign(str, strTemp - str);

			if (*strTemp == '[')
				addrTemp = strTemp;

			if (*strTemp == ']')
				addr.assign(addrTemp+1, strTemp - addrTemp - 1);

			strTemp++;
		}
	}

	void ssUnixCallStack::GetCallStack(std::string& out)
	{
		void *array[15] = { 0 };
		size_t size = 0;
		char** strings = 0;
		std::string cmd;
		std::string exe;
		std::string addr;
		std::ostringstream os;
		char tmp[1024] = { 0 };
		FILE* pp = 0;
		size = backtrace(array, 15);
		strings = backtrace_symbols(array, size);

		for (size_t i = 0; i < size; i++)
		{
			cmd.clear();
			exe.clear();
			addr.clear();

			ParseName(strings[i], exe, addr);
			os<<"["<<addr<<"]"<<"[";

			cmd = "addr2line -f -e ";
			cmd += exe+" "+addr;
			pp = popen(cmd.c_str(), "r"); //建立管道
			if (!pp)
			{
				continue;
			}

			while (fgets(tmp, sizeof(tmp), pp) != NULL)
			{
				size_t tmpLen = strlen(tmp);
				if (tmp[tmpLen - 1] == '\n')
				{
					tmp[tmpLen - 1] = '\0'; //去除换行符
				}
                os<<tmp;
			}
			os<<std::endl;
			pclose(pp); //关闭管道
		}
        out = os.str();
	}

}
